#include "matrix.h"
 
int Matrix::RANK=2;
H5std_string Matrix::ROW_NUM("RowNum");
H5std_string Matrix::COL_NUM("COLNum");

Matrix::Matrix(int rows, int cols, double d)
:CHDF5GroupObject(){
	rowN=rows;
	colN=cols;
	size=rows*cols;

	data=new double[size];

	for (int i=0; i<size; i++) data[i] = d;

	PredType dataType(PredType::NATIVE_DOUBLE);
	dims=new hsize_t[RANK];
	dims[0]=rows;
	dims[1]=cols;
	hdf5DataSet=new CHDF5DataSetObject(RANK,dims,dataType);

}

Matrix::~Matrix()
{
	if (data!=NULL)
	{
		delete[] data;
	}
	if (dims!=NULL)
	{
		delete[]dims;
	}
	if (hdf5DataSet!=NULL)
	{
		delete hdf5DataSet;
	}
}

void Matrix::printMatrix()
{
	for (int i=0;i<rowN;i++)
	{
		for (int j=0;j<colN;j++)
		{
			cout<<data[i*j];
			if (j!=colN-1)
			{
				cout<<",";
			}
		}
		cout<<endl;
	}
}

void Matrix::writeData(const H5std_string& location, const H5std_string &datasetName)
{
	H5std_string path=location+"/"+datasetName;

	hdf5DataSet->write(h5_file,path,data);
	DataSpace attr_dataspace = DataSpace(H5S_SCALAR);
	IntType attrDType(PredType::NATIVE_INT);
	hdf5DataSet->createAttribute(h5_file,path,ROW_NUM,attrDType,&rowN);
	hdf5DataSet->createAttribute(h5_file,path,COL_NUM,attrDType,&colN);
}

void Matrix::appendData(const H5std_string& location, const H5std_string &datasetName)
{
	H5std_string path=location+"/"+datasetName;
	hdf5DataSet->append(h5_file,path,data);

	IntType attrDType(PredType::NATIVE_INT);
	int r;
	hdf5DataSet->readAttribute(h5_file,path,ROW_NUM,attrDType,&r);
	r+=rowN;
	hdf5DataSet->modifyAttribute(h5_file,path,ROW_NUM,attrDType,&r);
	int c;
	hdf5DataSet->readAttribute(h5_file,path,COL_NUM,attrDType,&c);
	c+=colN;
	hdf5DataSet->modifyAttribute(h5_file,path,COL_NUM,attrDType,&c);
}

void Matrix::readData(const std::string &location, const H5std_string& dataSetName)
{
	H5std_string path(location);
	path.append("/");
	path.append(dataSetName);

	int size=hdf5DataSet->getSize(h5_file,path);
	data=new double[size];
	hdf5DataSet->read(h5_file,path,data);
}

int Matrix::write(const std::string &filename, const std::string &location, const std::string &groupName)
{
	int res=0;

	try
	{
		Exception::dontPrint();
		if (h5_file==NULL || h5_file->getFileName()!=filename)
		{
			h5_file=new H5File(filename,H5F_ACC_TRUNC);
		}

		if (createGroups(location,groupName))
		{
			writeData(location+"/"+groupName,"data");
		
			res=1;
		}
	}
	catch( FileIException error )
	{
		errMsg=error.getDetailMsg();
	}
	return res;
}
int Matrix::read(const std::string &filename, const std::string &location,const H5std_string& groupName)
{
	int res=0;

	try
	{
		Exception::dontPrint();

		if (h5_file==NULL || h5_file->getFileName()!=filename)
		{
			h5_file=new H5File(filename,H5F_ACC_RDONLY);
		}

		H5std_string groupPath=location+"/"+groupName;
		if (isGroupExist(groupPath))
		{
			readData(groupPath,"data");
			IntType attrDType(PredType::NATIVE_INT);
			hdf5DataSet->readAttribute(h5_file,groupPath+"/data",COL_NUM,attrDType,&colN);
			hdf5DataSet->readAttribute(h5_file,groupPath+"/data",ROW_NUM,attrDType,&rowN);
			res=1;
		}
	}
	// catch failure caused by the H5File operations
	catch( FileIException error )
	{
		errMsg=error.getDetailMsg();
	}
	return res;
}

int Matrix::append(const std::string &filename, const std::string &location, const std::string &groupName)
{
	int res=0;

	try
	{
		Exception::dontPrint();
		if (h5_file==NULL || h5_file->getFileName()!=filename)
		{
			h5_file=new H5File(filename,H5F_ACC_TRUNC);
		}

		H5std_string path=location+"/"+groupName;
		appendData(path,"data");
		res=1;
	}
	catch( FileIException error )
	{
		errMsg=error.getDetailMsg();
	}
	return res;
}